package com.ooolong.expression;

public class ONode {

	public static final int TYPE_OOBJECT = 0;
	public static final int TYPE_FUNCTION = 1;
	public static final int TYPE_OPERATOR = 3;
	public static final int TYPE_TEXT = 4;

	protected String name;
	protected int type;
	protected OObject value;

	protected ONode firstChild;
	protected ONode lastChild;
	protected ONode previousSibling;
	protected ONode nextSibling;
	protected ONode parent;
	protected int childCount = 0;

	public ONode(OObject obj) {
		this.value = obj;
	}

	public ONode appendChild(ONode newChild) {
		return insertBefore(newChild, null);
	}

	public ONode insertBefore(ONode newChild, ONode refChild) {
		if (newChild == null) {
			return null;
		}

		boolean flag = false;
		ONode node = firstChild;
		while (node != null) {
			if (newChild == node) {
				return null;
			}
			if (refChild == node) {
				flag = true;
			}
			node = node.getNextSibling();
		}

		if (this.firstChild == null) {
			this.firstChild = newChild;
			this.firstChild.parent = this;
			this.lastChild = this.firstChild;
		} else {
			if (refChild == null || !flag) {
				this.lastChild.nextSibling = newChild;
				this.lastChild.nextSibling.parent = this;
			} else {
				ONode originalNextSibling = refChild.nextSibling;
				ONode insertNode = newChild;
				insertNode.parent = this;
				if (originalNextSibling == null) {
					this.lastChild = refChild.nextSibling;
				} else {
					insertNode.nextSibling = originalNextSibling;
				}
				insertNode.previousSibling = refChild;
				refChild.nextSibling = insertNode;
			}
		}
		this.childCount++;
		return newChild;
	}

	public ONode getParentNode() {
		return this.parent;
	}

	public int getChildCount() {
		return this.childCount;
	}

	public ONode getFirstChild() {
		return this.firstChild;
	}

	public ONode getLastChild() {
		return this.lastChild;
	}

	public ONode getPreviousSibling() {
		return this.previousSibling;
	}

	public ONode getNextSibling() {
		return this.nextSibling;
	}

	public String getNodeName() {
		return this.name;
	}

	public OObject getNodeValue() {
		return this.value;
	}

	public void setNodeValue(OObject nodeValue) {
		this.value = nodeValue;
	}

	public int getNodeType() {
		return this.type;
	}

	public OObject execute() throws ExpressionException {
		if (this.getChildCount() == 0) {
			return this.value.execute(null);	
		}
		OObject[] args = new OObject[this.getChildCount()];
		ONode node = this.getFirstChild();
		int i = 0;
		while (node != null) {
			args[i] = node.getNodeValue();
			node = node.getNextSibling();
		}
		return this.value.execute(args);
	}
}
